home *** CD-ROM | disk | FTP | other *** search
- /* file: ENGINE1.PL {main code for MIKE rule/frame engine} */
- /* see also ENGINE2.PL for more! */
- /* *************
- M I K E
- *************
- Micro Interpreter for Knowledge Engineering
- {written in Edinburgh-syntax Prolog}
-
- Copyright (C) 1989, 1990 The Open University (U.K.)
-
- This software accompanies Open University Study Pack PD624, 'KNOWLEDGE
- ENGINEERING'. Complete sets of study pack materials may be obtained from:
-
- Learning Materials Sales Office
- The Open University
- P.O. Box 188
- Milton Keynes MK7 6DH, U.K.
-
- Tel: [+44] (908) 653338
- Fax: [+44] (908) 653744
- */
- /* ENGINE1.PL & ENGINE2.PL contain the essential innards of MIKE.
- Some auxilliary code is contained in the files UTIL.PL and IO.PL,
- and the kernel of the forward chaining executive loop is in FC_EXEC.PL
- ENGINE1.PL & ENGINE2.PL are subdivided into six main parts, as follows:
- 1. Backward chaining
- 2. Frame manipulation
- 3. Demon processing
- (N.B. the last three parts are in file ENGINE2.PL)
- 4. Top level
- 5. Forward chaining (left hand side conditions)
- 6. Forward chaining (right hand side actions)
- */
- /* ================ (1) B A C K W A R D C H A I N I N G =============== */
-
- /* prove1 invokes the workhorse prove, but wraps it inside
- some MIKE tracing information, settable by user request.
- (Tracing is set up by a call to ?- tracing. It is defined in UTIL.PL ) */
-
- prove1(Goal,Depth) :-
- when_enabled('show backward chaining' for Goal/Depth),
- prove(Goal,Depth),
- when_enabled('show outcome of backward chaining' for Goal/Depth).
-
- prove1(Goal,Depth) :-
- enabled('show outcome of backward chaining',' enabled ',_),
- write('<- '),tab(Depth),write('- '),conj_write(Goal),nl,
- !,
- fail.
-
- /* Top level invocation of prove (usually done via deduce <pattern> ) */
- prove((A&B)) :- /* Conjunction of goals */
- !,
- prove1((A&B),0). /* set initial depth to zero */
-
- prove(X) :- /* Singleton goal */
- prove1(X,0). /* set initial depth to zero */
-
- /* prove/2 is the main meta-level interpreter */
- /* case 1: conjunction of goals... tackle head, then rest */
- prove((Head & Rest),D) :-
- prove1(Head,D), /* use prove1 to invoke optional tracing info... */
- (Rest = (_ & _) , prove(Rest,D); /* Rest is conjunct? no trace */
- not(Rest = (_ & _)), prove1(Rest,D)). /* Rest is singleton? prove1 trace OK */
-
- prove((A&B),_):- !,fail. /* only arrive here if above calls fail */
-
- /* case 2: A disjunction of goals */
- prove((A or B),D) :-
- prove1(A,D), !.
- prove((_ or B),D) :-
- prove1(B,D).
-
- /* case 3, e.g. prove(the Slot of Object is Filler) is handled below
- by the call to in_wm (now covered by case 6) */
-
- /* cases 4a-4b: special traps for relational operators > and <.
- The code for >= or =< is equally trivial */
- prove(the Slot of Object > Value,D) :-
- !,
- fetch(Object, Slot, Filler, [Object], _),
- Filler > Value.
- prove(the Slot of Object < Value,D) :-
- !,
- fetch(Object, Slot, Filler, [Object], _),
- Filler < Value.
-
- /* case 5a: instead of 'Foo is in class Bar' we say 'Foo instance_of Bar' */
- prove(X instance_of Y,D) :-
- !,
- X instance_of Y with _. /* simple pattern-match in database, ignore _ */
- /* case 5b: analogous to case 5a, but this time for subclass_of */
- prove(X subclass_of Y,D) :-
- !,
- X subclass_of Y with _. /* simple pattern-match in database, ignore _ */
-
- /* case 6: allow the system to ask the user for a value. This may also
- be used to check a value, if you specify one. If the user
- specifies values and the value doesn't match with the one
- the user gives at query-time, the goal will fail. */
- prove((query X),D):-
- query X.
-
- /* case 7: check that the thing is not already in working memory. This
- would be the case of, say, an unstructured fact eg. [kettle,on] */
- prove(WME,_):-
- in_wm(WME). /* N.B. the code for in_wm(WME) now handles case 3, too,
- namely frame access of the form: the X of Y is Z */
-
- /* case 8: retrieve backward chaining rule from database, and prove premises.
- N.B. only a single conclusion is allowed in rule (i.e. Horn clause form) */
- prove(Conc,D) :-
- (rule Name backward if Premise then Conc), /* single conclusion only!!! */
- D1 is D + 1, /* increase depth for recursive proof */
- when_enabled('show chosen rule' for /* optional trace display */
- [(rule Name backward if Premise then Conc)]),
- prove1(Premise,D1). /* recursive proof of premise(s) */
-
- /* =============== (2) F R A M E M A N I P U L A T I O N ============= */
-
- /* fetch is the main frame-traversal utility.
- Fourth argument is a 'history list' to perform cycle detection
- Fifth argument tells us where recursive lookup terminates,
- i.e. from which ultimate object the property has been inherited, which could
- be useful for fancier implementation, to reveal that, say,
- the filler of slot FOO was inherited from class BAR.
- Most of the work is done by contains, described below */
-
- fetch(Object, Attribute, Value, History, TerminalObject) :-
- (Object instance_of Class with Body), /* get from DB */
- traverse_body(Object,Body,Attribute,
- slot(value(V),inheritance(I),cardinality(C))), /* arg 3 is OUTPUT here */
- ((I=[supersede];I=supersede),not(V=[]),!,'pd624 member'(Value,V) ;
- 'pd624 member'(Value,V)). /* fall through to next clause on btrack */
-
- fetch(Object, Attribute, Value, History, TerminalObject) :-
- (Object subclass_of Class with Body), /* alternative way to get it */
- traverse_body(Object,Body,Attribute,
- slot(value(V),inheritance(I),cardinality(C))), /* arg 3 OUTPUT here */
- ((I=[supersede];I=supersede),not(V=[]),!,'pd624 member'(Value,V) ;
- 'pd624 member'(Value,V)). /* fall through to next clause on btrack */
-
- fetch(Object,Attribute,Value,CycleList,TerminalNode):-
- isa_linked(Object,Super), /* search up class links */
- \+ 'pd624 member'(Super, CycleList), /* loop detector */
- fetch(Super,Attribute,Value,[Super|CycleList],TerminalNode).
-
- fetch1(Object,Attribute,Value,_,Object):-
- (Object instance_of Class with Body),
- contains(Body,Attribute:Value).
-
- fetch1(Object,Attribute,Value,_,Object):-
- (Object subclass_of Class with Body),
- contains(Body,Attribute:Value).
-
- fetch1(Object,Attribute,Value,CycleList,TerminalNode):-
- isa_linked(Object,Super),
- \+ 'pd624 member'(Super,CycleList),
- fetch1(Super,Attribute,Value,[Super|CycleList],TerminalNode).
-
- /* store/3 adds new slot-filler info at run time
- COMPATIBILITY NOTE: Be sure that the object definitions are INTERPRETED in
- MacPROLOG, or DYNAMIC in Quintus Prolog, so that the database can be updated
- correctly */
- store(Object, Attribute, NewValue) :-
- var(NewValue),
- 'pd624 write'(['ERROR: Illegal use of frames. You are not allowed to'
- ,nl,'have a variable as a frame slot filler.',nl,
- 'You tried to note the ',Attribute,' of ',Object,' is a variable. ',nl,
- '*** FRAME ',Object,' NOT UPDATED ***',nl]),!.
- store(Object, Attribute, NewValue) :- (Object
- instance_of Class with Body), !, subst(Object,(Attribute:Old),
- (Attribute:NewValue), Body, NewBody), retract((Object
- instance_of Class with Body1)), assert((Object instance_of
- Class with NewBody)),
- if_added_demon_check(NewBody,Object,Attribute,NewValue,Class).
- store(Object, Attribute, NewValue) :- (Object subclass_of Class
- with Body), !, subst(Object,(Attribute:Old),
- (Attribute:NewValue), Body, NewBody), retract((Object
- subclass_of Class with Body1)), assert((Object subclass_of Class
- with NewBody)),
- if_added_demon_check(NewBody,Object,Attribute,NewValue,Class).
- store(Object, Attribute, NewValue) :- assert((Object instance_of
- 'Newly Created Object' with
- Attribute:NewValue)).
-
- if_added_demon_check(NewBody,Object,A,V,C):-
- 'pd624 cmember'(A:Body,NewBody),
- if_added_demon(Body,Object,A,V,C).
- if_added_demon_check(NewBody,Object,A,V,C):-
- if_added_demon([],Object,A,V,C).
-
- /* subst: slot-filler substitution
- Args are as follows:
- 1: (input) object for ?self substitution
- 2: (input) old slot:filler combo we want over-written
- 3: (input) new slot:filler combo we want in place of oldie
- 4: (input) 'Body' of the frame, typically a long conjunct ...,...,...,...
- 5: (ouput) 'NewBody', i.e. the old Body with new stuff replacing old
- */
- subst(Object,Attribute:_, Attribute:New, (Attribute:[H|T],Rest),
- (Attribute:NewList,Rest)):-
- subst_facet(Attribute:New,[H|T],[H|T],NewList,Object).
- subst(Object,Attribute:_, Attribute:New, Attribute:[H|T],
- Attribute:NewList):-
- subst_facet(Attribute:New,[H|T],[H|T],NewList,Object).
-
-
- subst(Object,Attribute:Old, Attribute:New, Attribute:Old, Attribute:New):-
- type_check([],Object,Attribute,New),
- cardinality_check([],Object,Attribute,New).
-
- subst(Object,Attribute1:Old1, Attribute:New, Attribute2:Old2,
- (Attribute2:Old2,Attribute:New)):-
- type_check([],Object,Attribute,New),
- cardinality_check([],Object,Attribute,New).
-
- subst(Object,Attribute:Old, Attribute:New, (Attribute:Old,Rest),
- (Attribute:New,Rest)):-
- type_check([],Object,Attribute,New),
- cardinality_check([],Object,Attribute,New).
-
- subst(Object,X,Y, (First,Rest), (First,NewRest)) :-
- subst(Object,X,Y,Rest,NewRest).
-
- /* substitute facet assumes that you can only change the value of an individual
- facet, not other facets like cardinality or type, which CANNOT be changed
- dynamically. The substitue does a change as opposed to an add, i.e.
- existing value(s) are destructively replaced. There is as yet no
- additional flag to AUGMENT an existing set of values, although
- section 4.2.2 of the MIKE reference manual shows how to accomplish this. */
-
- /* variables A:V typically refer to Attribute:Value, which we tend
- to use synomynously with Slot:Filler */
-
- subst_facet(A:V,Body,[value:V|Rest],[value:V|Rest],Object):-
- type_check(Body,Object,A,V),
- cardinality_check(Body,Object,A,V).
- subst_facet(A:V,Body,[value:V1|Rest],[value:V|Rest],Object):-
- type_check(Body,Object,A,V),
- cardinality_check(Body,Object,A,V).
- subst_facet(A:V,B,[H|Rest],[H|Output],Object):-
- subst_facet(A:V,B,Rest,Output,Object).
-
- /* searching up 'isa' chain can either involve 'instance_of' or
- alternatively 'subclass_of' */
- isa_linked(X, Y) :-
- X instance_of Y with _ .
- isa_linked(X, Y) :-
- X subclass_of Y with _ .
-
- /* ---------- c o n t a i n s ---------------------------
- this searches down the (usually compound) 'Body', looking for a
- slot:filler combination. For example, suppose that we're looking for
- age:34 in some particular frame. By the time contains/2 is invoked
- (by fetch), we don't care what particular frame we're examining,
- but instead are looking in detail at the 'Body' of that frame, e.g.
- contains((has: fleas, eats: meat, age: 34), age:34)
- We therefore have to do 2 things...
- a) 'traverse' the body, CDR'ing down the line until we're at
- the right slot,
- b) see whether we can reconcile the goods we actually found with the
- slot:filler combination we set out to find.
- The magic is that when we have found the relevant slot, we ALSO
- want to convert it to what we call "NormalFacetForm" to avoid
- the problem arising from three different ways of specifying
- frames (e.g. simple, compound, complex). Therefore, when we find
- the relevant slot we invoke a workhorse called 'compose' which
- takes in a particular term and transforms it into our so-called
- NormalFacetForm.
- Thus there are only two calls to invoke:
- */
- contains(Body, Slot:Filler) :- /* Body & Slot normally input, Filler output */
- traverse_body(Body,Slot,NormalFacetForm),
- reconcilable(NormalFacetForm,Filler).
-
- /* --------- t r a v e r s e - b o d y -------------------------
- This 'CDRs' down the compound body looking for a match of slot names,
- and (more importantly) invokes compose/2, which
- takes in a particular term and transforms it into our so-called
- NormalFacetForm, so that we dont have to sweat about which way
- the user happened to specify the contents of a
- frame (e.g. simple, compound, complex).
- */
-
- /* case 1a: just a single slot, and it is the one we want */
- traverse_body(Object,Slot:Term,Slot,NormalFacetForm) :-
- !,
- compose(Object,Term, NormalFacetForm).
- traverse_body(Object,Slot:Term1,Slot1,NormalFacetForm) :-
- if_needed(Object,Object,Slot1,Term),
- compose(Object,Term,NormalFacetForm), !.
- /* case 2: a conjunction of slots, and first one is the one we want */
- traverse_body(Object,(Slot:Term, Rest), Slot, NormalFacetForm) :-
- compose(Object,Term, NormalFacetForm),
- !.
- /* case 3: a conjunction of slots, so we CDR on down the line */
- traverse_body(Object,(_, Rest), Slot, NormalFacetForm) :-
- traverse_body(Object,Rest, Slot, NormalFacetForm).
-
- /* -------------- c o m p o s e ------------------------------
- This is where we suffer for letting the user specify frames
- in any of three different ways. compose/2 takes its first frame's argument
- (a typical filler) as input, and converts into a 'normalised' form.
- For consistency, unitary values are always converted to a 1-element
- list, so that the value facet is ALWAYS a list.
- Here are some input/ouput examples, wherein IN is always the
- first argument to compose, and OUT is always the second
- argument:
-
- IN: meat
- OUT: slot(value([meat]), inheritance(supersede), cardinality(any))
-
- IN: [meat, bread]
- OUT: slot(value([meat, bread]), inheritance(supersede),
- cardinality(any))
-
- IN: [value: cheese, inheritance: merge, cardinality: 4]
- OUT: slot(value([cheese]), inheritance(merge), cardinality(4))
-
- Now, for the code...
-
- case 1: 'simple'
- this is an atomic filler, so just whack it into the value facet
- */
-
- compose(Object,X, slot(value([X]), inheritance(supersede),
- cardinality(any))) :-
- atomic(X),
- !.
-
- /* case 2: 'compound'
- this is a list of atomic fillers, e.g. [meat, potatoes], so do the
- same */
- compose(Object,[A|B], slot(value([A|B]),
- inheritance(supersede),
- cardinality(any))) :-
- atomic(A),
- !.
-
- /* case 3: 'complex'
- to get this far, the fillers must be in the complex form
- of [<facetX.Y>:<filler>, etc.], so we work through the list separately
- for each of our important facets, using a workhorse utility called
- force_membership which either finds the relevant item, or shoves
- the default value (e.g. 'supersede' for inheritance) in the right place
- */
- compose(Object,FacetFillerList, slot(value(V), inheritance(I),
- cardinality(C))) :-
- force_membership(Object,value : V, FacetFillerList),
- force_membership(Object,inheritance : I, FacetFillerList),
- force_membership(Object,cardinality : C, FacetFillerList).
-
- /* --------- f o r c e - m e m b e r s h i p ------------------
- arg1 is OUTPUT, arg2 INPUT
- */
- /* first check the value --- if the value is absent or unknown
- then look to see if there is an if_needed (access rule) demon */
- force_membership(Object,value: V,List):-
- \+ 'pd624 member'(value:V,List),
- if_needed1(Object,value:V,List).
- force_membership(Object,value: V,List):-
- ( 'pd624 member'(value: unknown,List); 'pd624 member'(value : [], List)),
- if_needed1(Object,value:V,List).
- /* compund (set of) fillers? then put them all in the facet */
- force_membership(Object,Facet : [Filler|Fillers], List) :-
- 'pd624 member'(Facet : [Filler|Fillers], List),
- !.
- /* unitary filler? then put it into a one-element list [Filler] */
- force_membership(Object,Facet : [Filler], List) :-
- 'pd624 member'(Facet : Filler, List),
- !.
-
- /* to get here, we must not have found anything, so we impose
- ('force') a default filler on the relevant facet, according to the
- name of the facet. e.g. if it is 'inheritance', we force 'supersede',
- if it is 'type', we force 'any', if it is 'value', we force '[]' */
-
- force_membership(Object,inheritance: [supersede], List) :- !.
- force_membership(Object,type: any, List) :- !.
- force_membership(Object,cardinality: any, List) :- !.
- /* all other facets, such as 'value', default to an empty list */
- force_membership(Object,Facet : [], List).
-
- /* ---------------- r e c o n c i l a b l e ----------------------
- having found our actual frame contents, now we really need to know
- whether the given Filler is consistent with the current value
- (remember that since we have converted to NormalFacetForm,
- the variable V below will always be a list.
- For now, we just use a membership test, but fancier options are
- possible, such as checking for consistency, looking for counter-
- examples, etc.
- Notice 4th argument (output) is used as a flag to pass back the
- type of inheritance mechanism */
-
- reconcilable(slot(value(V), inheritance(I), cardinality(C)),
- Filler ) :-
- 'pd624 member'(Filler,V).
-
-
- /* ----------------- Type and Cardinality checking --------------------
- (a) cardinality must be defined by number, or a range in the form
- LowerBound-HigherBound. The arguments ARE ORDER SENSITIVE!
- (b) type checking is only done for a particular slot in
- which the value is located. */
-
- type_check(Body,Object,Attribute,Value):-
- 'pd624 member'(type : T,Body),!,
- type_consistency(T,Object,Attribute,Value).
- type_check(_,Object,Attribute,Value):-
- isa_tc_check(Object,Object,type,Attribute,Value).
- type_check(_,_,_,_).
- cardinality_check(Body,Object,Attribute,Value):-
- 'pd624 member'(cardinality : C,Body), !,
- cardinality_consistency(C,Object,Attribute,Value).
- cardinality_check(_,Object,Attribute,Value):-
- isa_tc_check(Object,Object,cardinality,Attribute,Value).
- cardinality_check(_,_,_,_).
-
- /* recursive checking up isa hierarchy */
- isa_tc_check(Thing,Original,Flag,Attribute,Value):-
- isa_linked(Thing,Parent),
- (Parent subclass_of _ with Body),
- 'pd624 cmember'(Attribute:List,Body),
- 'pd624 member'(Flag:Check,List),
- choose_test(Flag,Check,Parent,Attribute,Value),!.
- isa_tc_check(Thing,Original,Flag,Attribute,Value):-
- isa_linked(Thing,Parent),
- (Parent instance_of _ with Body),
- 'pd624 cmember'(Attribute:List,Body),
- 'pd624 member'(Flag:Check,List),
- choose_test(Flag,Check,Parent,Attribute,Value),!.
-
- isa_tc_check(Thing,Original,Flag,Attribute,Value):-
- isa_linked(Thing,Parent),
- isa_tc_check(Parent,Original,Flag,Attribute,Value).
- isa_tc_check(_,_,_,_,_). /* so it always wins */
-
- choose_test(type,Check,Object,Attribute,Value):-
- type_consistency(Check,Object,Attribute,Value).
- choose_test(cardinality,Check,Object,Attribute,Value):-
- cardinality_consistency(Check,Object,Attribute,Value).
-
- /* any is the default case so for efficiency let's check for it first */
- type_consistency(any,_,_,_):- !.
- type_consistency(A,_,_,V):-
- isa_linked(V,A).
- type_consistency(A,_,_,V):-
- isa_linked(V,Something),
- type_consistency(A,_,_,Something).
- type_consistency(integer,_,_,V):-
- integer(V),!.
- type_consistency(nonvar,_,_,V):-
- nonvar(V),!.
- type_consistency(atom,_,_,V):-
- atomic(V),!.
- type_consistency(list,_,_,[H|T]).
- type_consistency(list,_,_,[]).
- type_consistency(Alternatives,_,_,V):-
- 'pd624 member'(V,Alternatives),!.
- type_consistency(T,Object,Attribute,Value):-
- 'pd624 write'(['Warning: "',Value,
- '" violates the "type" facet of "',Object,'" for slot "',Attribute,
- '" ',
- nl,'which specifies type : ',T,'. ',
- nl,'(but proceeding anyway)',nl]),!.
-
- /* the default cardinality is 'any'. As this will probably occur more
- often than any other case, for efficiency check for it first */
- cardinality_consistency(any,_,_,_).
- cardinality_consistency(1,Object,Attribute,Value):- /* cardinality one,
- then check to see if the slot filler is atomic */
- atomic(Value).
- cardinality_consistency(A-B,Object,Attribute,Value):-
- 'pd624 list length'(Value,Length),
- Length >= A,
- Length =< B.
- cardinality_consistency(Num,Object,Attribute,Value):-
- 'pd624 list length'(Value,Num). /* this will also cater for list of
- length one should they exist for some perverse reason */
- cardinality_consistency(Number,Object,Attribute,Value):-
- 'pd624 write'(['Warning: "',Value,'" violates the "cardinality" facet of "',
- Object,'" for slot "',Attribute,'"',nl,
- 'which specifies cardinality : ',Number,'. ',nl,
- '(but proceeding anyway)',nl]).
-
-
- /* =================== (3) D E M O N P R O C E S S I N G ============ */
- /* if_added demons are 'change_rules' in the text
- if_needed are called 'access_rules' */
-
- if_added_demon(Body,Object,A,V,Parent):-
- 'pd624 member'(change_rule : What_to_do,Body),
- process_if_added(What_to_do,Object,A).
-
- if_added_demon(Body,Object,Attr,Val,Parent):-
- find_the_superior_body(Parent,New_body),
- 'pd624 cmember'(Attr:ABody,New_body),
- 'pd624 member'(change_rule : Method,ABody),!,
- unify_value(Val,ABody),
- process_if_added(Method,Object,Attr).
- if_added_demon(Body,Object,Attr,Val,Parent):-
- isa_linked(Parent,Super_parent),
- if_added_demon(Body,Object,Attr,Val,Super_parent).
- if_added_demon(B,O,A,V,P).
-
- unify_value(Value,Body):-
- 'pd624 member'(value:Value,Body).
- unify_value(A,B). /* when the two will not unify */
-
- find_the_superior_body(Object,Body):-
- (Object instance_of _ with Body).
- find_the_superior_body(Object,Body):-
- (Object subclass_of _whoever with Body).
-
- 'pd624 cmember'(A,(A,_)).
- 'pd624 cmember'(A,(_,Rest)):-
- 'pd624 cmember'(A,Rest).
- 'pd624 cmember'(A,A).
-
- process_if_added(Method,Object,Attr):-
- process_method(Method,Object,Attr).
- process_if_added(Method,Object,Attr):-
- write('WARNING... The following method failed: '),write(Method),nl,
- write('from the object frame '),write(Object),nl.
-
-
- if_in_wm(A or B,Obj):-
- if_in_wm(A,Obj), !.
- if_in_wm(_ or B,Obj):-
- if_in_wm(B,Obj), !.
- if_in_wm(Pattern1 & Rest,Obj) :-
- !,
- if_in_wm(Pattern1,Obj),
- if_in_wm(Rest,Obj).
- if_in_wm(the Attr of ?self is What,Object):-
- in_wm(the Attr of Object is What).
- if_in_wm(true,_).
- if_in_wm(Pattern,_) :- /*singleton*/
- in_wm(Pattern).
-
- process_method((if Ifs then Thens),Object,Attr):-
- 'pd624 replace'(?self,Object,Ifs,NewIfs),
- if_in_wm(NewIfs,Object),
- parse_first(Thens,Object,Attr).
-
- parse_first(A & B,Object,Attribute):-
- parse_first(A,Object,Attribute),!,
- parse_first(B,Object,Attribute).
-
- /* PATCH 7th. September 1990.
- the following makes the consequences of if added demons consistent
- with that of forward chaining rules. Instead of the previous limitation
- regarding the use of ?self which was limited to the pattern
- the X of ?self is Y, ?self can now be used arbitrarily in a pattern
- e.g. [likes, ?self, beer] or loves(?self,mary). */
-
- parse_first(Term,Object,A):-
- 'pd624 replace'(?self,Object,Term,NTerm),
- perform1(NTerm,_,_,_).
-
- /* ---------------- COMPATIBILITY NOTE -------------------------
- In the next two predicate definitions, we test for
- real(Term)
- If your dialect of Prolog does not cater for real numbers,
- you can comment out those tests
- ---------------------------------------------------------------- */
-
- 'pd624 replace'(O,N,O1,O1):- var(O1),!.
- 'pd624 replace'(O,N,O,N).
- 'pd624 replace'(Old,New,Term,Term) :-
- (integer(Term) ; real(Term) ; atom(Term)),
- not(Term=Old).
- 'pd624 replace'(Old,New,Term,Term1) :-
- 'pd624 compound'(Term),
- functor(Term,F,N),
- functor(Term1,F,N),
- 'pd624 replace'(N,Old,New,Term,Term1).
- 'pd624 replace'(N,Old,New,Term,Term1) :-
- N>0,
- arg(N,Term,Arg),
- 'pd624 replace'(Old,New,Arg,Arg1),
- arg(N,Term1,Arg1),
- N1 is N-1,
- 'pd624 replace'(N1,Old,New,Term,Term1).
- 'pd624 replace'(0,Old,New,Term,Term1).
-
- 'pd624 compound'(X) :-
- not(atom(X)),
- not(real(X)), /* see above compatibility notice */
- not(integer(X)).
-
- decide_what_to_store(the Attribute of Object is Value):-
- store(Object,Attribute,Value).
- decide_what_to_store(_). /* to cater for unstructured facts */
-
- /* the output is always a list */
- find_value((if Ifs then Thens),Object,Attribute,Value):-
- demon_prove(Ifs,Object,Attribute),
- demon_rhs(Thens,Object,Attribute,Value).
-
- demon_prove(X or Y,Object,Attribute):-
- demon_prove(X,Object,Attribute);
- demon_prove(Y,Object,Attribute),!.
- demon_prove(X & Y,Object,Attribute):-
- demon_prove(X,Object,Attribute),
- demon_prove(Y,Object,Attribute).
- demon_prove(true,_,_). /* for lhs of the form if true then Then */
- demon_prove(the Attribute of Object is What,Object,Attribute):-
- 'pd624 write'(['Error: the ',Attribute,' of ',Object,
- ' is being re-invoked in the very demon that is trying to find',nl,
- 'its value. This request will cause the method to fail',nl]).
- demon_prove(the Attribute of ?self is What,Object,Attribute):-
- 'pd624 write'(['Error: the ',Attribute,' of ',Object,
- ' is being re-invoked in the very demon that is trying to find',nl,
- 'its value. This request will be cause the method to fail',nl]).
-
- demon_prove(the A of ?self is What,Object,_):-
- prove(the A of Object is What).
- demon_prove(X,_,_) :- prove(X).
-
- demon_rhs(the A of B is C,_,_,C):- /* PATCH 7/9/90 */
- !. /* i.e. do nothing, because C is simply returned un-cached */
- demon_rhs(make_value X,Object,Attribute,X):-
- !,
- note the Attribute of Object is X.
- demon_rhs(A,B,C,_):-
- 'pd624 write'(['Warning: the access_rule method for ',B,' of ',C,
- 'contains a right-hand-side which does not supply a value.',nl,
- 'Right-hand-sides that do must be of the form the A of B is C',
- 'or they must contain the key-word "make_value" followed by a value.',
- nl]),!.
-
- list_check([P|P1],[P|P1]).
- list_check(P,[P]).
-
- /* this only gets called when we know we have a demon in the current
- facet filler, in which case we don't go chasing up the isa chain */
- if_needed1(Object,value:Value,Body):-
- 'pd624 member'((access_rule : What_to_do),Body),
- find_value(What_to_do,Object,' this is a dummy value to pass ',Value).
-
- /* the standard case. You don't find a value so you try going up the
- isa chain in order to find an appropriate demon at some stage in
- your ancestry */
- if_needed(BaseObject,Object,Slot,Term):-
- (Object instance_of Super with _),
- find_the_superior_body(Super,NewBody),
- if_needed_process(BaseObject,Slot,Term,Super,NewBody).
- if_needed(BaseObject,Object,Slot,Term):-
- (Object subclass_of Super with _),
- find_the_superior_body(Super,NewBody),
- if_needed_process(BaseObject,Slot,Term,Super,NewBody).
- if_needed(BaseObject,Object,Slot,Term):-
- (Object subclass_of Super with _),
- if_needed(BaseObject,Super,Slot,Term).
- if_needed(BaseObject,Object,Slot,Term):-
- (Object instance_of Super with _),
- if_needed(BaseObject,Super,Slot,Term).
-
- if_needed_process(BaseObject,Attr,Val,Super,Body):-
- 'pd624 cmember'(Attr:ABody,Body),
- 'pd624 member'(access_rule:Method,ABody),
- !,
- (find_value(Method,BaseObject,Attr,Val);
- write('WARNING... The following access_rule demon failed: '),nl,
- write(Method),nl,write('In the frame '),write(Super),nl,!,fail).
-
- /* more forward chaining code is in file ENGINE2.PL */